package v3

import (
	"bytes"
	"crypto/sha256"
	"encoding/binary"
	"encoding/gob"
	"time"
)

type Block struct {
	//版本号
	Version uint64
	//父级区块hash= 前一个hash值
	PreHash []byte
	//梅克尔根(就是⼀个哈希值，v4版本介绍）
	MerkleRoot []byte
	//时间戳
	Timestamp uint64
	//难度值
	Difficulty uint64
	//随机数
	Nonce uint64

	//-----//当前区块哈希值(为了⽅便实现，所以将区块的哈希值放到了区块中),实际上应该不存在与这里,应该放到K:v数据库的K位置上
	Hash []byte
	//交易数据
	Data []byte
}

// 序列化成字节流
func (b *Block) Serialize() []byte {
	var result bytes.Buffer
	enc := gob.NewEncoder(&result)
	enc.Encode(b)
	return result.Bytes()
}

// 反序列化
func Deserialize(data []byte) *Block {
	var b Block
	dec := gob.NewDecoder(bytes.NewReader(data))
	dec.Decode(&b)
	return &b
}

// 创建区块
func NewBlock(PreHash []byte, Data string) *Block {
	block := Block{
		Version:    00,
		PreHash:    PreHash,
		MerkleRoot: []byte{},
		Timestamp:  uint64(time.Now().Unix()),
		Difficulty: 0,
		Nonce:      0,
		Data:       []byte(Data),
	}
	//block.SetHash()
	ofWork := NewProofOfWork(&block)
	//挖矿的hash赋值给对应的区块
	hash, nonce := ofWork.run()
	block.Hash = hash
	block.Nonce = nonce
	return &block
}

func Uint64ToBytes(num uint64) []byte {
	var buf = bytes.Buffer{}
	err := binary.Write(&buf, binary.BigEndian, num)
	if err != nil {
		panic(err)
	}
	return buf.Bytes()
}

// 计算区块的 hash
func (block *Block) SetHash() {
	s := [][]byte{
		Uint64ToBytes(block.Version),
		block.PreHash,
		block.MerkleRoot,
		Uint64ToBytes(block.Timestamp),
		Uint64ToBytes(block.Difficulty),
		Uint64ToBytes(block.Nonce),
		block.Data,
	}
	data := bytes.Join(s, []byte{})
	bytes := sha256.Sum256(data)
	block.Hash = bytes[:]
}
